import { ChangeDetectionStrategy, Component, ElementRef, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subject } from 'rxjs';
import { cloneDeep, filter, forEach, uniqueId } from 'lodash';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { DatatableComponent, DateRangePickerComponent, FilterItem, LvDateRangeTag, OptionItem, TypeUtils } from '@iux/live';
import { ENTER } from '@angular/cdk/keycodes';

@Component({
  selector: 'app-custom-filter',
  templateUrl: './custom-filter.component.html',
  styles: [
    `
      .lv-icon-host {
        cursor: pointer;
      }
      .customer-filter {
        line-height: 0;
      }
      .name-filter-title {
        font-size: 12px;
        color: #4d4d4d;
      }
      .name-filter-input {
        margin: 4px 0 16px;
      }
      .name-filter-operation {
        display: flex;
        justify-content: flex-end;

        .lv-button:last-child {
          margin-left: 16px;
        }
      }
      .customer-date-range.lv-popover .lv-popover-inner {
        padding: 0;
      }
    `,
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
})
export class CustomFilterComponent implements OnInit, OnDestroy {
  data;
  value;
  idFilterValue;
  nameFilterValue;
  nameFilterTrueValue: string;
  ageFilterValue;
  cacheData;
  search$ = new Subject<string>();
  destroy$ = new Subject<void>();
  options: FilterItem[];
  cacheOptions: FilterItem[];
  rangeDate: [Date, Date] = null;
  rangeDatePanelVisible = false;
  idSearchPanelVisible = false;
  nameSearchPanelVisible = false;
  randomPanelVisible = false;
  typeUtils = TypeUtils;
  currentInput: LvDateRangeTag = 'start';

  @ViewChild(DatatableComponent, { static: false }) lvTable: DatatableComponent;
  @ViewChild('randomPopover', { static: false }) popover;
  @ViewChild('datePopover', { static: false }) datePopover;
  @ViewChild('dateRangePicker') dateRangePicker: DateRangePickerComponent;
  @ViewChild('primaryButton', { read: ElementRef }) primaryButton: ElementRef<HTMLElement>;
  @ViewChild('nameFilterInput') nameFilterInput: ElementRef<HTMLElement>;

  constructor() {}

  ngOnInit() {
    this.initData();
  }

  initData() {
    this.data = Array.from({ length: 10 }).map((item, key) => this.initUser(key));
    this.cacheData = cloneDeep(this.data);
    this.searchSubscribe();
    this.initOptions();
  }

  initOptions() {
    this.options = [
      {
        key: 0,
        label: 'odd',
        value: false,
      },
      {
        key: 1,
        label: 'even',
        value: true,
      },
    ];
    this.cacheOptions = cloneDeep(this.options);
  }

  initUser(key: number) {
    return {
      id: uniqueId('uid'),
      name: `user${key}`,
      age: 10 + key,
      expand: false,
      random: parseInt(`${Math.random() * 100}`, 10),
      date: new Date(`2020-02-${key + 1}`),
    };
  }

  updateSearch(e: any) {
    this.search$.next(e);
  }

  searchSubscribe() {
    this.search$.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe(value => {
      this.filterById(value);
    });
  }

  filterById(value: string) {
    this.idFilterValue = value;
    this.lvTable.filter({ key: 'id', value, filterMode: 'contains' });
  }

  filterByName(value: string) {
    this.nameFilterTrueValue = value;
    if (value === null || value === undefined) {
      return;
    }
    this.lvTable.filter({ key: 'name', value, customFilter: this.customFilterName });
  }

  filterByAge(value: string) {
    this.ageFilterValue = value;
    this.lvTable.filter({ key: 'age', value, customItemFilter: this.customFilterAge });
  }

  popoverBeforeOpen = () => {
    this.nameFilterValue = this.nameFilterTrueValue;
    this.options = cloneDeep(this.cacheOptions);
  };

  toggleRandom(source: FilterItem) {
    source.selected = !source.selected;
  }

  submit() {
    const selected = this.getSelectedRandomOptions(this.options).map(item => item.value);
    this.cacheOptions = cloneDeep(this.options);
    this.data = filter(cloneDeep(this.cacheData), item => selected.includes(item.random % 2 === 0) || !selected.length);
    this.randomPanelVisible = false;
  }

  reset() {
    forEach(this.options, item => {
      item.selected = false;
    });
    this.submit();
  }

  customFilterName(data, option) {
    return filter(data, item => item[option.key].includes(option.value));
  }

  customFilterAge(data, filter: { [key: string]: any }) {
    return `${data[filter.key]}`.includes(filter.value);
  }

  getSelectedRandomOptions(options: OptionItem[]): OptionItem[] {
    return filter(options, 'selected');
  }

  onOk(): void {
    if (this.rangeDate?.[0] && this.rangeDate?.[1]) {
      this.closePanel();
    } else {
      this.currentInput === 'start' ? (this.currentInput = 'end') : (this.currentInput = 'start');
    }
  }

  closePanel(): void {
    if (this.rangeDate[0] > this.rangeDate[1]) {
      [this.rangeDate[0], this.rangeDate[1]] = [this.rangeDate[1], this.rangeDate[0]];
    }
    this.lvTable.filter({
      key: 'date',
      value: this.rangeDate,
      filterMode: 'timeIn',
    });
    this.rangeDatePanelVisible = false;
  }

  rangeTagChange(tag: LvDateRangeTag): void {
    this.currentInput = tag;
  }

  disableOk(): boolean {
    const curValue = this.currentInput === 'start' ? this.rangeDate?.[0] : this.rangeDate?.[1];
    return (
      !curValue ||
      this.dateRangePicker?.getDateDisableState(curValue, this.currentInput, false) ||
      this.dateRangePicker?.checkDateDisableStatus(curValue, this.currentInput)
    );
  }

  getOkLabel(): string {
    if (this.rangeDate?.[0] && this.rangeDate?.[1]) {
      return 'Confirm';
    } else {
      return this.currentInput === 'start' ? 'Choose End Date' : 'Choose Start Date';
    }
  }

  resetDate(): void {
    this.rangeDate = null;
    this.lvTable.removeFilter('date');
    this.rangeDatePanelVisible = false;
  }

  cancelRangeDate(): void {
    if (this.rangeDate?.[0] && this.rangeDate?.[1]) {
      return;
    }
    this.resetDate();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  getSelectedRangeDate() {
    // rangeDate 清空时为[null, null]
    if (this.rangeDate?.length) {
      return JSON.stringify(this.rangeDate) !== JSON.stringify([null, null]) || this.rangeDatePanelVisible;
    }
    return this.rangeDate || this.rangeDatePanelVisible;
  }

  openRangeDatePanel() {
    this.rangeDatePanelVisible = !this.rangeDatePanelVisible;
  }

  openRandomPanel() {
    this.randomPanelVisible = !this.randomPanelVisible;
  }

  openIdSearchPanel() {
    this.idSearchPanelVisible = !this.idSearchPanelVisible;
  }

  openNameSearchPanel() {
    this.nameSearchPanelVisible = !this.nameSearchPanelVisible;
    setTimeout(() => {
      this.nameFilterInput?.nativeElement?.focus();
    }, 250); // 等待面板打开动画
  }

  confirmName(e: KeyboardEvent): void {
    if (e.keyCode === ENTER) {
      this.primaryButton.nativeElement.click();
    }
  }
}
